package cn.android666.ping

import android.os.Bundle
import android.os.Message
import android.widget.CompoundButton
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import cn.android666.ping.databinding.ActivitySettingsBinding
import org.greenrobot.eventbus.EventBus
import java.util.regex.Pattern

class SettingsActivity : AppCompatActivity() {

    private val binding by lazy { ActivitySettingsBinding.inflate(layoutInflater) }
    private val defaultDestination = "192.168.1.123"
    private val defaultPackageSize = "1348"
    private val defaultInterval = "0.2"
    private val defaultDeadline = "60"
    private val defaultCount = "60"
    private val defaultTimeout = "1"
    private val defaultIsCheckedDeadline = false
    private val defaultIsCheckedCount = false
    private val defaultIsCheckedTime = false
    private val defaultIsCheckedDontFragment = true
    private val defaultIsCheckedManualEditCommand = false

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(binding.root)
        setTitle("设置")
        initView()
        initListener()
    }

    private fun initListener() {
        binding.saveSettings.setOnClickListener { saveSettings() }
        binding.restoreDefault.setOnClickListener { initAsDefault() }

        val editTextInputChangeListener = EditTextInputChangeListener { refreshPingCommandEditText() }
        binding.destinationEdit.addTextChangedListener(editTextInputChangeListener)
        binding.packetSizeEdit.addTextChangedListener(editTextInputChangeListener)
        binding.intervalEdit.addTextChangedListener(editTextInputChangeListener)
        binding.deadlineEdit.addTextChangedListener(editTextInputChangeListener)
        binding.countEdit.addTextChangedListener(editTextInputChangeListener)
        binding.timeoutEdit.addTextChangedListener(editTextInputChangeListener)

        val checkBoxChangeListener = CompoundButton.OnCheckedChangeListener { _, _ -> refreshPingCommandEditText() }
        binding.deadlineCheckBox.setOnCheckedChangeListener(checkBoxChangeListener)
        binding.countCheckBox.setOnCheckedChangeListener(checkBoxChangeListener)
        binding.timeoutCheckBox.setOnCheckedChangeListener(checkBoxChangeListener)
        binding.dontFragmentCheckBox.setOnCheckedChangeListener(checkBoxChangeListener)
        binding.manualEditCommandCheckBox.setOnCheckedChangeListener { _, isChecked -> onManualEditCommandCheckBoxCheckedChanged(isChecked) }
    }

    private fun saveSettings() {
        if (binding.manualEditCommandCheckBox.isChecked) {
            PersistentVariables.isCheckedManualEditCommand = true
            savePingCommand()
            return
        }

        val ip = binding.destinationEdit.text.trim().toString()
        val sizeStr = binding.packetSizeEdit.text.trim().toString()
        val time = binding.deadlineEdit.text.trim().toString()
        if (ip.isBlank()) {
            Toast.makeText(this, "请输入IP", Toast.LENGTH_SHORT).show()
            return
        }
        if (sizeStr.isBlank()) {
            Toast.makeText(this, "请输入数据包大小", Toast.LENGTH_SHORT).show()
            return
        }
        if (time.isBlank()) {
            Toast.makeText(this, "请输入要ping多久", Toast.LENGTH_SHORT).show()
            return
        }

        if (!isValidIpAddress(ip)) {
            Toast.makeText(this, "您输入的IP地址格式有误！", Toast.LENGTH_SHORT).show()
            return
        }

        saveOptions()
        savePingCommand()
    }

    private fun savePingCommand() {
        // 正则功能为：把多个连续空格替换为单个空格，以预防手动输入时多输入了空格
        val pingCommand = binding.pingCommandEdit.text.toString().trim().replace(Regex("\\s{2,}"), " ")
        if (pingCommand.isNotEmpty()) {
            PersistentVariables.pingCommand = pingCommand
            Toast.makeText(applicationContext, "保存成功", Toast.LENGTH_SHORT).show()
            EventBus.getDefault().post(Message.obtain(null, Whats.REFRESH_COMMAND))
            finish()
        } else {
            Toast.makeText(this, "命令不能为空", Toast.LENGTH_SHORT).show()
        }
    }

    private fun initView() = with(binding) {
        // 保存的ping命令不为空，则说明有保存过配置，则所有配置都用之前保存的配置，否则用默认配置
        if (PersistentVariables.pingCommand.isNotEmpty()) {
            destinationEdit.setText(PersistentVariables.destination)
            packetSizeEdit.setText(PersistentVariables.packageSize)
            intervalEdit.setText(PersistentVariables.interval)
            deadlineEdit.setText(PersistentVariables.deadline)
            countEdit.setText(PersistentVariables.count)
            timeoutEdit.setText(PersistentVariables.timeout)
            deadlineCheckBox.isChecked = PersistentVariables.isCheckedDeadline
            countCheckBox.isChecked = PersistentVariables.isCheckedCount
            timeoutCheckBox.isChecked = PersistentVariables.isCheckedTimeout
            dontFragmentCheckBox.isChecked = PersistentVariables.isCheckedDontFragment
            manualEditCommandCheckBox.isChecked = PersistentVariables.isCheckedManualEditCommand
            pingCommandEdit.isEnabled = manualEditCommandCheckBox.isChecked

            if (manualEditCommandCheckBox.isChecked) {
                pingCommandEdit.setText(PersistentVariables.pingCommand)
            }
        } else {
            initAsDefault()
        }

        onManualEditCommandCheckBoxCheckedChanged(manualEditCommandCheckBox.isChecked)
        refreshPingCommandEditText()
    }

    /** 当手动编辑命令复选框选中状态发生变化时 */
    private fun onManualEditCommandCheckBoxCheckedChanged(isChecked: Boolean) = with(binding) {
        destinationEdit.isEnabled = !isChecked
        packetSizeEdit.isEnabled = !isChecked
        intervalEdit.isEnabled = !isChecked
        deadlineEdit.isEnabled = !isChecked
        countEdit.isEnabled = !isChecked
        timeoutEdit.isEnabled = !isChecked
        deadlineCheckBox.isEnabled = !isChecked
        countCheckBox.isEnabled = !isChecked
        timeoutCheckBox.isEnabled = !isChecked
        dontFragmentCheckBox.isEnabled = !isChecked
        pingCommandEdit.isEnabled = isChecked
        if (!isChecked) {
            refreshPingCommandEditText()
        }
    }

    private fun initAsDefault() = with(binding) {
        destinationEdit.setText(defaultDestination)
        packetSizeEdit.setText(defaultPackageSize)
        intervalEdit.setText(defaultInterval)
        deadlineEdit.setText(defaultDeadline)
        countEdit.setText(defaultCount)
        timeoutEdit.setText(defaultTimeout)
        deadlineCheckBox.isChecked = defaultIsCheckedDeadline
        countCheckBox.isChecked = defaultIsCheckedCount
        timeoutCheckBox.isChecked = defaultIsCheckedTime
        dontFragmentCheckBox.isChecked = defaultIsCheckedDontFragment
        manualEditCommandCheckBox.isChecked = defaultIsCheckedManualEditCommand
    }

    private fun saveOptions() = with(binding) {
        PersistentVariables.destination = destinationEdit.text.toString().trim()
        PersistentVariables.packageSize = packetSizeEdit.text.toString().trim()
        PersistentVariables.interval = intervalEdit.text.toString().trim()
        PersistentVariables.deadline = deadlineEdit.text.toString().trim()
        PersistentVariables.count = countEdit.text.toString().trim()
        PersistentVariables.timeout = timeoutEdit.text.toString().trim()
        PersistentVariables.isCheckedDeadline = deadlineCheckBox.isChecked
        PersistentVariables.isCheckedCount = countCheckBox.isChecked
        PersistentVariables.isCheckedTimeout = timeoutCheckBox.isChecked
        PersistentVariables.isCheckedDontFragment = dontFragmentCheckBox.isChecked
        PersistentVariables.isCheckedManualEditCommand = manualEditCommandCheckBox.isChecked
    }

    private fun refreshPingCommandEditText() = with(binding) {
        if (binding.manualEditCommandCheckBox.isChecked) {
            // 手动编辑时不需要刷新
            return
        }

        val destination = destinationEdit.text.toString().trim()
        val packageSize = packetSizeEdit.text.toString().trim()
        val interval = intervalEdit.text.toString().trim()
        val isCheckedDeadline = deadlineCheckBox.isChecked
        val isCheckedCount = countCheckBox.isChecked
        val isCheckedTimeout = timeoutCheckBox.isChecked
        val isCheckDontFragment = dontFragmentCheckBox.isChecked
        val deadline = deadlineEdit.text.toString().trim()
        val count = countEdit.text.toString().trim()
        val timeout = timeoutEdit.text.toString().trim()

        val args = mutableListOf<String>()
        args.add("/system/bin/ping")

        // 指定每个ping包的数据部分大小（单位为字节）
        args.add("-s")
        args.add(packageSize)

        // 设置发送ICMP Echo Request数据包的时间间隔（单位为秒）
        args.add("-i")
        args.add(interval)

        // 设置ping的最后期限，即到这个时间后ping就会结束，单位为秒
        if (isCheckedDeadline) {
            args.add("-w")
            args.add(deadline)
        }

        // 设置ping的次数，即发送多少个ICMP Echo Request数据包
        if (isCheckedCount) {
            args.add("-c")
            args.add(count)
        }

        // 设置超时，即等待ICMP Echo Reply数据包的时间（单位为秒）
        if (isCheckedTimeout) {
            args.add("-W")
            args.add(timeout)
        }

        // 设置禁用数据分片（即不将数据分片为多个 smaller packets）
        if (isCheckDontFragment) {
            args.add("-M")
            args.add("do")
        }

        // 设置目标主机的IP地址或域名，表示要测试连通性的目标。
        args.add(destination)

        pingCommandEdit.setText(args.joinToString(" "))
    }

    /**
     * 验证给定的ip地址是否有效
     * @param ip
     */
    private fun isValidIpAddress(ip: String?): Boolean {
        if (ip.isNullOrBlank()) return false
        val regex = "(2(5[0-5]{1}|[0-4]\\d{1})|[0-1]?\\d{1,2})(\\.(2(5[0-5]{1}|[0-4]\\d{1})|[0-1]?\\d{1,2})){3}"
        val pattern = Pattern.compile(regex)
        val matcher = pattern.matcher(ip)
        return matcher.matches()
    }
}